#include <rtthread.h>

struct exception_stack_frame
{
    rt_uint32_t r0;     //会自动保存到线程的栈中
    rt_uint32_t r1;
    rt_uint32_t r2;
    rt_uint32_t r3;
    rt_uint32_t r12;
    rt_uint32_t lr;
    rt_uint32_t pc;
    rt_uint32_t psr;
};

struct stack_frame
{
    /*r4~r11 register*/
    rt_uint32_t r4;     //手动保存  地址最低,下面地址依次增加
    rt_uint32_t r5;
    rt_uint32_t r6;
    rt_uint32_t r7;
    rt_uint32_t r8;
    rt_uint32_t r9;
    rt_uint32_t r10;
    rt_uint32_t r11;

    struct exception_stack_frame exception_stack_frame;
};
//现在明白了无欲望则钢  一旦人有了欲望,那么就好控制了！！
/*flag in interrupt handling*/
rt_uint32_t rt_interrupt_from_thread,rt_interrupt_to_thread;  //这里存放的是线程栈sp的地址(指针的地址)
rt_uint32_t rt_thread_switch_interrupt_flag;
/*exception hook*/
static rt_err_t (* rt_exception_hook)(void * context)=RT_NULL;   //函数指针变量

/**
 * @brief This function will initialize thread stack
 * 
 * @param tentry : the entry of thread
 * @param parameter :the parameter of entry
 * @param stack_addr :the beginning stack address  stack:栈  heap:堆
 * @param texit :the function will be called when thread exit  existance
 * 
 * @return stack address
 */
rt_uint8_t * rt_hw_stack_init(void *tentry,                     //线程的入口地址
                              void *parameter,                  //形参会存到R0中
                              rt_uint8_t *stack_addr,
                              void *texit)
{   //这里的stack_addr(rt_hw_stack_init中的stack_addr)其实等于 (void *)((char *)thread->stack_addr + thread->stack_size - 4)
    struct stack_frame *stack_frame;
    rt_uint8_t *stk;
    unsigned long i;  
    //stack_addr指向高位地址        生于忧患,死于安乐
    stk=stack_addr+sizeof(rt_uint32_t);  //获取栈顶指针
    /*rt_hw_stack_init在调用的时候,传给stack_addr的是(栈顶指针-4)  为毛????*/
    stk=(rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk,8); //让stk指针向下8字节对齐(相对于低地址) 高字节为栈顶,低字节为栈低
    //通常4字节对齐就可以了,但为了兼容浮点运算,所以要8字节对齐  上面也是获取小规模的
    stk-=sizeof(struct stack_frame);

    stack_frame=(struct stack_frame*)stk;

    /*init all register*/
    for(i=0;i<sizeof(struct stack_frame)/sizeof(rt_uint32_t);i++)
    {       //循环16次
        ((rt_uint32_t *)stack_frame)[i]=0xdeadbeef;  //*(pointer+x) == pointer[x]
    }
    //要多做好事
    stack_frame->exception_stack_frame.r0=(unsigned long)parameter; //r0: argument
    stack_frame->exception_stack_frame.r1=0;                        //r1
    stack_frame->exception_stack_frame.r2=0;                        //r2
    stack_frame->exception_stack_frame.r3=0;                        //r3
    stack_frame->exception_stack_frame.r12=0;                       //r12
    stack_frame->exception_stack_frame.lr=(unsigned long)texit;     //lr  //存储返回的地址
    stack_frame->exception_stack_frame.pc=(unsigned long)tentry;    //entry point,pc
    stack_frame->exception_stack_frame.psr=0x01000000L;             //PSR

    /*return task's current stack address*/
    return stk;   //栈顶的位置就是一些存寄存器的东东
}

/**
 * This function set the hook,which is invoked on fault exception handling
 * 
 * @param exception_handle the exception handling hook function
 */
void rt_hw_exception_install(rt_err_t (*exception_handle)(void * context))  //形参是一个函数指针
{
    rt_exception_hook=exception_handle;  //坑爹呀！！！ 这钱不能收呀！！  宁愿不说话,也别乱说话
}

#define     SCB_CFSR       (*(volatile const unsigned *)0xE000ED28)     /*Configurable Fault Status Register*/
#define     SCB_HFSR       (*(volatile const unsigned *)0xE000ED2C)     /*HardFault Status Register*/
#define     SCB_MMAR       (*(volatile const unsigned *)0xE000ED34)     /*MemManage Fault Address register*/
#define     SCB_BFAR       (*(volatile const unsigned *)0xE000ED38)     /*Bus Fault Address Register*/

#define     SCB_CFSR_MFSR  (*(volatile const unsigned char *)0xE000ED28) /*Memory-management Fault Status Register*/
#define     SCB_CFSR_BFSR  (*(volatile const unsigned char *)0xE000ED29) /*Bus Fault Status Register*/
#define     SCB_CFSR_UFSR  (*(volatile const unsigned short *)0xE000ED2A) /*Usage Fault Status Register*/

#ifdef      RT_USING_FINSH
static void usage_fault_track(void)
{   //这东东我也不太懂
    rt_kprintf("usage fault:\n");
    rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR);

    if(SCB_CFSR_UFSR & (1<<0))
    {
        /* [0]:UNDEFINSTR */
        rt_kprintf("UNDEFINSTR ");
    }

    if(SCB_CFSR_UFSR & (1<<1))
    {
        /* [1]:INVSTATE */
        rt_kprintf("INVSTATE ");
    }

    if(SCB_CFSR_UFSR & (1<<2))
    {
        /* [2]:INVPC */
        rt_kprintf("INVPC ");
    }

    if(SCB_CFSR_UFSR & (1<<3))
    {
        /* [3]:NOCP */
        rt_kprintf("NOCP ");
    }

    if(SCB_CFSR_UFSR & (1<<8))
    {
        /* [8]:UNALIGNED */
        rt_kprintf("UNALIGNED ");
    }

    if(SCB_CFSR_UFSR & (1<<9))
    {
        /* [9]:DIVBYZERO */
        rt_kprintf("DIVBYZERO ");
    }

    rt_kprintf("\n");
}

static void bus_fault_track(void)
{
    rt_kprintf("bus fault:\n");
    rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR);

    if(SCB_CFSR_BFSR & (1<<0))
    {
        /* [0]:IBUSERR */
        rt_kprintf("IBUSERR ");
    }

    if(SCB_CFSR_BFSR & (1<<1))
    {
        /* [1]:PRECISERR */
        rt_kprintf("PRECISERR ");
    }

    if(SCB_CFSR_BFSR & (1<<2))
    {
        /* [2]:IMPRECISERR */
        rt_kprintf("IMPRECISERR ");
    }

    if(SCB_CFSR_BFSR & (1<<3))
    {
        /* [3]:UNSTKERR */
        rt_kprintf("UNSTKERR ");
    }

    if(SCB_CFSR_BFSR & (1<<4))
    {
        /* [4]:STKERR */
        rt_kprintf("STKERR ");
    }

    if(SCB_CFSR_BFSR & (1<<7))
    {
        rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR);
    }
    else
    {
        rt_kprintf("\n");
    }
}

static void mem_manage_fault_track(void)
{
    rt_kprintf("mem manage fault:\n");
    rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR);

    if(SCB_CFSR_MFSR & (1<<0))
    {
        /* [0]:IACCVIOL */
        rt_kprintf("IACCVIOL ");
    }

    if(SCB_CFSR_MFSR & (1<<1))
    {
        /* [1]:DACCVIOL */
        rt_kprintf("DACCVIOL ");
    }

    if(SCB_CFSR_MFSR & (1<<3))
    {
        /* [3]:MUNSTKERR */
        rt_kprintf("MUNSTKERR ");
    }

    if(SCB_CFSR_MFSR & (1<<4))
    {
        /* [4]:MSTKERR */
        rt_kprintf("MSTKERR ");
    }

    if(SCB_CFSR_MFSR & (1<<7))
    {
        /* [7]:MMARVALID */
        rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR);
    }
    else
    {
        rt_kprintf("\n");
    }
}

static void hard_fault_track(void)
{
    if(SCB_HFSR & (1UL<<1))
    {
        /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */
        rt_kprintf("failed vector fetch\n");
    }

    if(SCB_HFSR & (1UL<<30))
    {
        /* [30]:FORCED, Indicates hard fault is taken because of bus fault,
                        memory management fault, or usage fault. */
        if(SCB_CFSR_BFSR)
        {
            bus_fault_track();
        }

        if(SCB_CFSR_MFSR)
        {
            mem_manage_fault_track();
        }

        if(SCB_CFSR_UFSR)
        {
            usage_fault_track();
        }
    }

    if(SCB_HFSR & (1UL<<31))
    {
        /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */
        rt_kprintf("debug event\n");
    }
}
#endif      /*RT_USING_FINSH*/

struct exception_info
{
    rt_uint32_t exc_return;
    struct stack_frame  stack_frame;
}

/**
 * @brief fault exception handler  这个函数会在HardFault_Handler中调用
 */
void rt_hw_hard_fault_exception(struct exception_info * exception_info)
{                               //结构体指针  勤奋是基础
    extern long list_thread(void);//一个外部函数      //exception_stack_frame
    struct stack_frame *context=&exception_info->stack_frame;

    if(rt_exception_hook != RT_NULL)   //异常钩子函数不为空,这个函数可以被执行
    {   //路走的太顺,不是啥好事！！！
        rt_err_t result;

        result=rt_exception_hook(exception_info);   //其实rt_exception_hook指向了一个外部函数,这里调用的就是外部函数
        if(result==RT_EOK)
        {
            return;
        }
    }
    //上面没有解决,才轮到下面来解决(上面解决了,就没上面事了) %08x 八位16进制,不足补零
    rt_kprintf("psr: 0x%08x\n",context->exception_stack_frame.psr);  //psr程序状态寄存器

    rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0);  //
    rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1);
    rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2);
    rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3);
    rt_kprintf("r04: 0x%08x\n", context->r4);
    rt_kprintf("r05: 0x%08x\n", context->r5);
    rt_kprintf("r06: 0x%08x\n", context->r6);
    rt_kprintf("r07: 0x%08x\n", context->r7);
    rt_kprintf("r08: 0x%08x\n", context->r8);
    rt_kprintf("r09: 0x%08x\n", context->r9);
    rt_kprintf("r10: 0x%08x\n", context->r10);
    rt_kprintf("r11: 0x%08x\n", context->r11);
    rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12);
    rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr);
    rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc);

    if(exception_info->exc_return &(1<<2))  //0x4  0100
    {   //进入到这里是怎么回事??
        rt_kprintf("hard fault on thread: %s\r\n\r\n",rt_thread_self()->name);

#ifdef  RT_USING_FINSH
        list_thread();
#endif  /*RT_USING_FINSH*/
    }
    else
    {
        rt_kprintf("hard fault on handler\r\n\r\n");   //这个是表示硬件错误出现在中断中吗???
    }
#ifdef  RT_USING_FINSH
    hard_fault_track();
#endif  
    while (1)
    {
        ;
    }
}